﻿//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    Crolengi, this program (a part of program) is gameengine based on C++\Directx
//    Copyright (C) 2008 Pashinin Anton Alekseevich (Crol)
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
//    (INCLUDING NEGLIGENCE OR OTHERWISE) 
//    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
//    EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//    Contacts: 
//    Mail: crolengi@gmail.com
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


#include "..\\StdAfx.h"

#ifndef Graphic_CC_included
#define Graphic_CC_included

#include "character.h"
#include "..\\Objects\\Static_CObject.h"
#include "..\\Objects\\CCamera.h"
#include "..\\Managers\\Camera_Manager.h"

float FPS_CORRECTOR = 1;


 float JUMP = 3.7;
 int DEF_GANTLET_JUMPS = 2;
 float DEF_GRAVITY = -200.6;
float GRAVITY = -3.0;
int GANTLET_JUMPS = 0;
//const NxVec3 GRAVITY_VEC = {0,-2.5,0};

// репорт рэйкаста для обработки динамических объектов
class myRaycastReport : public NxUserRaycastReport
{
	virtual bool onHit(const NxRaycastHit& hit)
	{
		int userData = (int)hit.shape->getActor().userData;
		userData |= 1;	// Mark as hit
		hit.shape->getActor().userData = (void*)userData;


      // worldRay
		NxCollisionGroup group = hit.shape->getGroup();
		

		NxActor& actor = hit.shape->getActor();
		if((1))//(actor.isDynamic())&&
		{
			NxF32 mass = actor.getMass();
			NxF32 coeff = 0;
			if(hit.distance<1)
				 coeff = 208000.0f*actor.getMass();
			else
			     coeff = 202000.0f*actor.getMass()/(hit.distance);

			



			if (coeff>90000000000.0) {
				coeff = 60000000000.0;
			}
			NxVec3 dir; 
			dir.x = -hit.worldNormal.x;
			dir.y = -hit.worldNormal.y-0.45;
			dir.z = -hit.worldNormal.z;

			if ((dir.x==0)&&(dir.z==0))
				 coeff =  coeff/1000.0;
			//actor.addForceAtPos(NxVec3(hit.u,0,hit.v)*coeff, hit.worldImpact, NX_IMPULSE);
			//if (actor.isSleeping())
			//actor.setAngularVelocity(NxVec3(0,0,0));
			//actor.setLinearVelocity(NxVec3(0,0,0));
			///actor.setMaxAngularVelocity(1000);
			//actor.setLinearDamping(0.20);
			//actor.setMaxLVelocity(100);
			//actor.setLinearVelocity(NxVec3(0,0,0));
			//actor.putToSleep();
			actor.addForceAtLocalPos(dir*coeff, NxVec3(0,0,0), NX_IMPULSE);

			//actor.
		return true;
		}
		return false;
	}
}gMyReport;

class myRaycastReport2 : public NxUserRaycastReport
{
	virtual bool onHit(const NxRaycastHit& hit)
	{
		//int userData = (int)hit.shape->getActor().userData;
		//userData |= 1;	// Mark as hit
		//hit.shape->getActor().userData = (void*)userData;


      // worldRay
		NxCollisionGroup group = hit.shape->getGroup();
		

		NxActor& actor = hit.shape->getActor();
		if(((group==GROUP_COLLIDABLE_NON_PUSHABLE)))//(actor.isDynamic())&&
		{
			//NxF32 mass = actor.getMass();
			//NxF32 coeff = 10000.0f*actor.getMass()/(hit.distance);
			actor.putToSleep();
			//actor.addForceAtPos(NxVec3(hit.u,0,hit.v)*coeff, hit.worldImpact, NX_IMPULSE);
			//if (actor.isSleeping())
			//actor.addForceAtLocalPos(NxVec3(0,10,0)*coeff, NxVec3(0,0,0), NX_IMPULSE);
			//actor.
		return true;
		}
		return false;
	}
}gMyReport2;




class Graphic_CC: public character
{
	public:
    Static_CObject* object;
	CLREngi_Camera*        camera;
    
	CLREngi_Camera_Manager *Camera_Manager;
	LPDIRECT3DDEVICE9      *pd3dDevice;

	NxActor *actor;
	float d3dMat[16];
    D3DXMATRIX matWorld;

	NxExtendedVec3 v3buff,v3buff_old;
	D3DXVECTOR3 LookVector;


	int CHARACTER_W,CHARACTER_H;

	bool space_activated,down_hit;

	

bool Init(int H, int W, Static_CObject* obj){
	object = obj;

	CHARACTER_W = W;
	CHARACTER_H = H;

	createCapsule(W,H);
	actor = con->getActor();

	CRLEngi_string name;
	name = "CC";
	camera = Camera_Manager->NewCamera(name,true);
	camera->Position.x = 2000.0;
	camera->Position.y = 2000.0;
	camera->Position.z = 2000.0;
	camera->Up.x = 0;
	camera->Up.y = 1;
	camera->Up.z = 0;
	camera->Right.x = 0;
	camera->Right.y = 0;
	camera->Right.z = 1;
	camera->Look.x =  object->Position.x;
	camera->Look.y =  object->Position.y;
	camera->Look.z =  object->Position.z;
	camera->CameraName = "CC";

	v3buff_old.x = v3buff_old.y = v3buff_old.z = 0;
	v3buff.x = v3buff.y = v3buff.z = 0;

    return true;		
}

void Render(){
	//float *aa;
   //GetPosition(aa);
  // v3buff.x = aa[0];
   //v3buff.x = aa[1];
   //v3buff.x = aa[2];

	v3buff = con->getDebugPosition();

	LookVector.x =  camera->Look.x - camera->Position.x;
	LookVector.y =  camera->Look.y - camera->Position.y;
	LookVector.z =  camera->Look.z - camera->Position.z;
	D3DXVec3Normalize(&LookVector,&LookVector);
 
	D3DXMATRIX rotate ;
	 D3DXMatrixLookAtLH(&rotate,&camera->Position,&camera->Look,&camera->Up);
  

	object->Position = D3DXVECTOR3(v3buff.x,v3buff.y,v3buff.z);
	//object->rotate(&rotate);
	//object->update_only_position();
	object->update_position();
	


	camera->Look.x =  object->Position.x;
	camera->Look.y =  object->Position.y+400;
	camera->Look.z =  object->Position.z;

	// if ((camera->Position.x - object->Position.x > 2500)||
		// (camera->Position.x - object->Position.x < -2500))
	   camera->Position.x -= v3buff_old.x - v3buff.x;

	// if ((camera->Position.z - object->Position.z > 2500)||
		// (camera->Position.z - object->Position.z < -2500))
	   camera->Position.z -= v3buff_old.z - v3buff.z;
	
	 camera->Position.y = object->Position.y + 2000.0;
	//camera->Position.z = object->Position.z;//+2000.0;

//	(con->getActor())->getGlobalPose().getColumnMajor44( d3dMat );
	//matWorld = d3dMat;
	//(*pd3dDevice)->SetTransform( D3DTS_WORLD, &matWorld );
	object->Render(1,true);

	v3buff_old = v3buff;
}

void update(float dt)
{
	DEF_GRAVITY = -7.0;///FPS_CORRECTOR;
   //JUMP         =  (240.0/FPS_CORRECTOR)/60;
	JUMP = 6.5;
	if(!con) return;

   if (GRAVITY>DEF_GRAVITY)
	   GRAVITY-=0.8/(GRAVITY-DEF_GRAVITY);


		NxF32 sharpness = 1.0f;
		
		NxU32 collisionFlags;
		NxVec3 d;
		d.x=vec[0];
		d.y=vec[1];
		d.z=vec[2];
		d= d*dt;

		d.y=GRAVITY*dt;
/*
		if (collisionFlags & NXCC_COLLISION_SIDES)  {
		vec[0]=0;vec[2]=0;
		}
	   if (collisionFlags & NXCC_COLLISION_DOWN )  {
		vec[1]=0;
		}else vec[1]=GRAVITY;		
*/
		NxRay worldRay;
		worldRay.dir = d;
		worldRay.dir.y = -0.15;

		//worldRay.dir.x = 0.0;
		//worldRay.dir.z = 0.0;
		v3buff = con->getDebugPosition();
		worldRay.orig.x = v3buff.x; 
		worldRay.orig.y = v3buff.y+100;
		worldRay.orig.z = v3buff.z;

		//worldRay.orig.x = 0; 
		//worldRay.orig.y = 5000;
		//worldRay.orig.z = 0;

		worldRay.dir.normalize();

        NxU32 nbShapes =0,nbShapes1 =0,nbShapes2 =0;
		//g_pScene->raycastClosestBounds(worldRay,NX_ALL_SHAPES,gMyReport,10,-1,0);
		//if ((worldRay.dir.x!=0)||(worldRay.dir.x!=0))
		 nbShapes = g_pScene->raycastAllShapes(worldRay, gMyReport, NX_ALL_SHAPES, 0xffffffff,CHARACTER_W+100);
         worldRay.dir.y = 0.75;
		 nbShapes1 = g_pScene->raycastAllShapes(worldRay, gMyReport, NX_ALL_SHAPES, 0xffffffff,CHARACTER_W+100);
		 
		 g_pScene->raycastAllShapes(NxRay(worldRay.orig,NxVec3(0,1,0)), gMyReport, NX_ALL_SHAPES, 0xffffffff,CHARACTER_H+50);



		 //g_pScene->raycastClosestShape(worldRay,NX_ALL_SHAPES,gMyReport,NX_ALL_SHAPES,1500);
		// проверка на то провалились ли мы под пол
		nbShapes2 = g_pScene->raycastAllShapes(NxRay(worldRay.orig,NxVec3(0,-1,0)), gMyReport2, NX_ALL_SHAPES, 0xffffffff,290);

		 
		if ((nbShapes<=1)&&(nbShapes1<=1)&&(nbShapes2<=1)){
		    con->move(d, COLLIDABLE_MASK, 0.001f, collisionFlags, sharpness);
		}else if (d.y>0) {
			d.x = 0;d.z = 0;
		 	con->move(d, COLLIDABLE_MASK, 0.001f, collisionFlags, sharpness);		
		}

		nbShapes2 = g_pScene->raycastAllShapes(NxRay(worldRay.orig,NxVec3(0,-1,0)), gMyReport2, NX_ALL_SHAPES, 0xffffffff,300);
		
		
		//else if ((nbShapes<=1)&&(nbShapes1<=1)){
			//d.x = 0;d.z = 0;
		//	con->move(d, COLLIDABLE_MASK, 0.0001f, collisionFlags, sharpness);
		//}
        
		
        // если мы таки провалились под пол, то срочно подъем!!
		if (nbShapes2>1){
			v3buff = con->getDebugPosition();
			if (GRAVITY<0)
			  GRAVITY = 0.5;
			else
			  GRAVITY +=0.1;

			d.y = GRAVITY;
			//con->move(d, COLLIDABLE_MASK, 0.0001f, collisionFlags, sharpness); // ?   
			con->move(d, GROUP_NON_COLLIDABLE, 0.001f, collisionFlags, sharpness);
		}

		 if( (collisionFlags & NXCC_COLLISION_DOWN )|| (collisionFlags & NXCC_COLLISION_SIDES) )  {
		   
			GRAVITY = DEF_GRAVITY;
			space_activated = false;
		}

		 if ((collisionFlags & NXCC_COLLISION_DOWN )&&(!(collisionFlags & NXCC_COLLISION_SIDES))){
			// GANTLET_JUMPS =0;
			  down_hit = true;
		 
		 }

		 if (collisionFlags & NXCC_COLLISION_UP ) {
			GRAVITY = 0.0;
		}

			 if ((collisionFlags & NXCC_COLLISION_SIDES )&&(!down_hit) ){
			GRAVITY = 0.0;
		}

		//NxU32 COLLIDABLE_MASK = NX_SF_STATICS|NX_SF_DYNAMICS;
		

		//if (collisionFlags & NXCC_COLLISION_SIDES)  {
		//con->move(-d, -1, 0.000001f, collisionFlags, sharpness);
        //vec[0]=0;vec[1]=0;vec[2]=0;
		//	;
		//}
/*
		v3buff = con->getPosition();
	    object->Position = D3DXVECTOR3(v3buff.x,v3buff.y,v3buff.z);

	   if (collisionFlags & NXCC_COLLISION_SIDES)  {
		vec[0]=0;vec[2]=0;
		}
	   if (collisionFlags & NXCC_COLLISION_DOWN )  {
		down_hit
		}
*/
}

void KeyboardInput(float  Time){

    unsigned char keys[256];
	GetKeyboardState( keys );
    //D3DXVECTOR3 tmppos,N;

	Time= (float)(Time/60);
		if (Time<0.05)Time=0.05 ;

	float MOVESPEED = 5;//2*Time;

	//JUMP = 15*Time;

	//GRAVITY *= GRAVITY;

	bool smthng = false;

	if( keys[0x41]  & 0x80 )//w
	{ 
		  // float a[3]; a[1] = -0.5;a[2] = 0;a[3] = 0;
		   SetVector(NxVec3(-MOVESPEED*LookVector.z,GRAVITY,MOVESPEED*LookVector.x));
		   smthng=true;
	}else if (!smthng) SetVector(NxVec3(0,GRAVITY,0));

	if( keys[0x44]  & 0x80 )
	{ 
		  // float a[3]; a[1] = -0.5;a[2] = 0;a[3] = 0;
		   SetVector(NxVec3(MOVESPEED*LookVector.z,GRAVITY,-MOVESPEED*LookVector.x));
		   smthng=true;
	}else if (!smthng) SetVector(NxVec3(0,GRAVITY,0));

	if( keys[0x57] & 0x80 )
	{ 
		  // float a[3]; a[1] = -0.5;a[2] = 0;a[3] = 0;
		   SetVector(NxVec3(MOVESPEED*LookVector.x,GRAVITY,MOVESPEED*LookVector.z));
		   smthng=true;
	}else if (!smthng) SetVector(NxVec3(0,GRAVITY,0));

	if( keys[0x53] & 0x80 )
	{ 
		  // float a[3]; a[1] = -0.5;a[2] = 0;a[3] = 0;
		   SetVector(NxVec3(-MOVESPEED*LookVector.x,GRAVITY,-MOVESPEED*LookVector.z));
		   smthng=true;
	}else if (!smthng) SetVector(NxVec3(0,GRAVITY,0));

	if(( keys[VK_SPACE] & 0x80 ))
	{   
		//if((GANTLET_JUMPS<DEF_GANTLET_JUMPS-1)&&(!down_hit)&&(!smthng))//&&(smthng)
           //     return;

		if ((!space_activated)&&((down_hit)||(!smthng))&&(GANTLET_JUMPS<DEF_GANTLET_JUMPS)){//&&(GANTLET_JUMPS<=DEF_GANTLET_JUMPS)){
		  
			if((!smthng)) {
				GANTLET_JUMPS++;
			}

			
			space_activated = true;
		  // float a[3]; a[1] = -0.5;a[2] = 0;a[3] = 0;
		   GRAVITY = JUMP;
		   

		   


		   SetVector(NxVec3(0,GRAVITY,0));
		   smthng=true;
		   down_hit = false;
		}
		
	}else {
		if (down_hit) GANTLET_JUMPS=0;
		space_activated = false;
	}

}
Graphic_CC(NxControllerManager* c,NxScene* s,LPDIRECT3DDEVICE9   *Device,CLREngi_Camera_Manager* CamMngr){
		
	CCMgr = c;
	g_pScene = s;	
	pd3dDevice = Device;

	Camera_Manager = CamMngr;

	space_activated = false;
	down_hit = false;

}

};

/// класс для обнаружения столкновений между character и объектами мира



#endif